#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import re
import json
from src.utils import ttutil
import gettext
import psutil
import webbrowser
import copy

# lang_zh_CN = gettext.translation('emulator_port', 'src/locale', ['zh_CN'])
# lang_zh_CN.install()
# _ = lang_zh_CN.gettext
domains = ['emulator_port']
languageDir = os.path.abspath('src/locale')
for domain in domains:
    gettext.bindtextdomain(domain, languageDir)
    gettext.textdomain(domain)
_ = gettext.gettext

_CONFIG_PATH = os.path.abspath(
    os.path.join(os.path.abspath(__file__), os.path.pardir, 'config.json'))
_FEEDBACK_URL = 'https://gitee.com/tp7309/TTEmulatorPortFinder'
_OFFICIAL_EMULATOR = 'official_emulator'

_EMULATORS = {}


class Emulator(object):
    def __init__(self, d):
        self.type = d['type']
        self.name = d['name']
        self.process_name = d['process_name']
        self.default_ports = d['default_ports']
        self.re_port = d.get('re_port')
        # 2: never tips
        # 1: tip when unknown emulator found
        # 0: tip when known emulator port change and unknown emulator found
        self.upload_tip_level = \
            d.get('upload_tip_level') if d.get('upload_tip_level') else 0


def get_processes(emulator):
    return [
        x for x in psutil.process_iter() if x.name() == emulator.process_name
    ]


def get_ports(emulator):
    ps = get_processes(emulator)
    print(
        _("{name}({type}) processes:").format(
            name=emulator.name, type=emulator.type))
    print(ps)
    ports = []
    if len(ps) >= 1 and len(ps) <= len(emulator.default_ports):
        for default_port in emulator.default_ports:
            print(default_port)
            result = ttutil.check_adb_connectable_by_port(
                default_port, auto_disconnect=False)
            print(result)
            if result:
                ports.append(default_port)
    if ports:
        return ports

    for p in ps:
        connections = [
            x.laddr for x in p.connections() if x.status == psutil.CONN_LISTEN
        ]
        print(connections)
        if emulator.re_port:
            ports += [
                int(x.port) for x in connections
                if re.match(emulator.re_port, str(x.port)) and x.port > 2000
            ]
        else:
            ports += [int(x.port) for x in connections if x.port > 2000]
    ports = ttutil.check_adb_connectable_by_ports(ports)
    return ports


def read_config(src=_CONFIG_PATH):
    with open(src, 'r', encoding='utf-8') as f:
        config = json.load(f)
    for e in config['emulators']:
        _EMULATORS[e['type']] = Emulator(e)


def write_config(config, dest=_CONFIG_PATH):
    with open(dest, 'w', encoding='utf-8') as f:
        json.dump(config, f, sort_keys=True, indent=4, ensure_ascii=False)


def update_config(changed_emulators, dest=_CONFIG_PATH):
    if not changed_emulators:
        return

    with open(dest, 'r', encoding='utf-8') as f:
        config = json.load(f)

    for e in changed_emulators:
        pr = ttutil.props(e)
        old_emulators = config['emulators']
        if pr['type'] in _EMULATORS:
            for index, old_e in enumerate(old_emulators):
                if old_e['type'] == pr['type']:
                    old_emulators[index] = pr
                    break
        else:
            config['emulators'].append(pr)

    write_config(config, dest=dest)


def is_known_port_changed(e, new_ports):
    if not e or e.upload_tip_level >= 1:
        return False
    old_ports = e.default_ports
    if not old_ports:
        old_ports = []
    if not new_ports:
        new_ports = []
    if len(new_ports) > len(old_ports):
        for port in old_ports:
            if port not in new_ports:
                return True
    else:
        for port in new_ports:
            if port not in old_ports:
                return True
    return False
    


def check_known_emulators():
    emulators = {}
    filtered = [_OFFICIAL_EMULATOR]
    ischanged = False
    for p in psutil.process_iter():
        if p.name() in filtered:
            continue
        filtered.append(p.name())
        for t, e in _EMULATORS.items():
            if e.process_name == p.name():
                print('..............................')
                result = get_ports(e)
                if result:
                    if not emulators.get(e.type):
                        emulators[e.type] = copy.deepcopy(e)
                    emulators[e.type].default_ports = result
                if not ischanged:
                    ischanged = is_known_port_changed(e, emulators[e.type].default_ports)
    return ischanged, emulators.values()


def check_unknown_emulators():
    emulators = {}
    for p in psutil.process_iter():
        for t, e in _EMULATORS.items():
            if e.process_name == p.name():
                continue
        connections = [
            x.laddr for x in p.connections() if x.status == psutil.CONN_LISTEN
        ]
        for conn in connections:
            if conn.port > 2000 and ttutil.check_adb_connectable_by_port(
                    conn.port):
                if not emulators.get(p.name()):
                    args = {
                        'type': p.name(),
                        'name': p.name(),
                        'process_name': p.name(),
                        'default_ports': [conn.port]
                    }
                    e = Emulator(args)
                    emulators[e.type] = e
                    if conn.port not in emulators[e.type].default_ports:
                        emulators[e.type].default_ports.append(conn.port)
    return emulators.values()


def dump(emulators):
    for e in emulators:
        print(json.dumps(e.__dict__))


def main():
    read_config()
    ischanged, result = check_known_emulators()
    if ttutil.check_has_connected_devices():
        print('\n')
        print(_("one active emulator found"))
        ttutil.sh('adb devices')
        return

    if result:
        print('\n')
        print(_("emulator has been found!"))
        dump(result)
    else:
        print(_('no known emulator found, try to find new emulator'))
        result = check_unknown_emulators()
        if len(result) <= 0:
            print(_("no adb connectable emulator found"))
            return
        dump(result)
        ischanged = True
    if ischanged:
        # update config
        update_config(result)
        print(
            _("new emulator config has been found! please paste '{config}' content to\n{url} by new issue!"
                ).format(config=_CONFIG_PATH, url=_FEEDBACK_URL))
        webbrowser.open_new_tab(_FEEDBACK_URL)


if __name__ == '__main__':
    main()
